package task

import (
	"encoding/xml"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"strings"

	"github.com/astaxie/beego"
	"github.com/opensourceways/server-common-lib/utils"

	"cvevulner/common"
	"cvevulner/taskhandler"

	"github.com/astaxie/beego/config"
	"github.com/astaxie/beego/logs"
)

// ProcCveOriginData Process raw data obtained by api
func ProcCveOriginData(prcNum, days, credibilityLevel, openeulerNum int, cveRef, owner string) (bool, error) {
	// Process raw data obtained by api
	ok, err := taskhandler.GetCveOriginData(prcNum, days, openeulerNum, credibilityLevel, cveRef, nil)
	if !ok {
		logs.Error("ProcCveOriginData, GetCveOriginData, err: ", err)
	}
	// Processing excel raw data
	okx, err := taskhandler.GetCveOriginExcelData(prcNum, days, openeulerNum, cveRef)
	if !okx {
		logs.Error("ProcCveOriginData, GetCveOriginExcelData, err: ", err)
	}
	return true, nil
}

// ParamsCveOriginData Processing cve raw data
func ParamsCveOriginData() error {
	defer common.Catchs()
	logs.Info("Start the task of generating cve raw data into cve library.")
	// Query the cve to be processed, 1: add; 2: modify
	BConfig, err := config.NewConfig("ini", "conf/app.conf")
	if err != nil {
		logs.Error("config init, error: ", err)
		return err
	}
	// The amount of data processed at a time
	prcnum, err := BConfig.Int("crontab::prcnum")
	if err != nil {
		logs.Error("crontab::prcnum, error:  ", err)
		return errors.New("value is nil")
	}
	// How many days have been processed to date data
	days, ok := BConfig.Int("crontab::days")
	if ok != nil {
		logs.Error("crontab::days, err:", err)
		return ok
	}
	// openeuler Number start value
	cveRef := BConfig.String("cve::cveref")
	openeulernum, ok := BConfig.Int("cve::openeulernum")
	if ok != nil {
		logs.Error("cve::openeulernum, err:", err)
		return ok
	}
	owner := BConfig.String("gitee::owner")
	// cve credibility level
	credibilityLevel, ok := BConfig.Int("cve::credibility_level")
	if ok != nil {
		logs.Error("cve::credibility_level, err:", err)
		return ok
	}
	// Get the data source of the table
	_, errx := ProcCveOriginData(prcnum, days, credibilityLevel, openeulernum, cveRef, owner)
	logs.Info("The task of generating cve original data into cve library is over.")
	return errx
}

func ReleaseUnaffectedCve() error {
	startTime := common.TimeStrSub(common.GetCurDate(), -90)

	accessToken := os.Getenv("GITEE_TOKEN")
	if len(accessToken) == 0 {
		return fmt.Errorf("triggerUnaffectedCve, issue token acquisition failed")
	}

	owner := beego.AppConfig.String("gitee::owner")
	unaffectYear := beego.AppConfig.DefaultInt("excel::unaffect_year", 2018)
	dir := beego.AppConfig.DefaultString("fileDir", "download")
	_ = common.CreateDir(dir)

	var unaffectcvrf = taskhandler.UnaffectCvrfSa{Xmlns: "http://www.icasi.org/CVRF/schema/cvrf/1.1",
		XmlnsCvrf: "http://www.icasi.org/CVRF/schema/cvrf/1.1"}
	cvrffileName := filepath.Join(dir, "cvrf-unaffected-cve-"+common.GetCurDate()+".xml")
	du := beego.AppConfig.DefaultString("excel::v_pack_20_03_url", "")
	csvPathList := strings.Split(du, ";")
	for _, branch := range csvPathList {
		branchs := strings.Split(branch, "@")
		if len(branchs) > 0 && branchs[0] != "" {
			taskhandler.UnaffectIssueProc(branchs[0], nil, nil, startTime,
				accessToken, owner, &unaffectcvrf, unaffectYear, nil)
		}
	}

	if len(unaffectcvrf.Vulnerability) == 0 {
		logs.Error("unaffected cve is empty, time:", startTime)
		return fmt.Errorf("unaffected cve is empty, time:%s", startTime)
	}

	_ = os.Remove(cvrffileName)
	xmlOutPut, outPutErr := xml.MarshalIndent(unaffectcvrf, "", "	")
	if outPutErr != nil {
		return outPutErr
	}

	xmlOutPutData := append([]byte(xml.Header), xmlOutPut...)
	_ = ioutil.WriteFile(cvrffileName, xmlOutPutData, os.ModePerm)

	uploadCvrfDir := beego.AppConfig.String("obs::download_cvrf_dir")

	_, localFileName := filepath.Split(cvrffileName)
	obsErr := taskhandler.PostFile(cvrffileName, uploadCvrfDir+localFileName)
	if obsErr != nil {
		logs.Error("upload file fail, obsErr: ", obsErr)
		return obsErr
	}

	syncUnCVEUrl := beego.AppConfig.String("reflink::openeuler_api") + "/cve-security-notice-server/syncUnCVE"
	client := utils.NewHttpClient(3)

	v := url.Values{}
	v.Set("username", beego.AppConfig.String("cve::user"))
	v.Set("password", beego.AppConfig.String("cve::pwd"))
	v.Set("cveNo", localFileName)

	req, _ := http.NewRequest(http.MethodPost, syncUnCVEUrl, strings.NewReader(v.Encode()))
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")

	var resp struct {
		Code int    `json:"code"`
		Msg  string `json:"msg"`
	}

	_, err := client.ForwardTo(req, &resp)
	if err != nil {
		return err
	}

	if resp.Code == 1 {
		logs.Error("release unaffected cve failed, err: ", resp.Msg)
		return nil
	}

	taskhandler.DelFile([]string{cvrffileName})

	return nil
}
